iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0
自我挑戰組

30 天 Node.js 探索:基礎、進階與實踐系列 第 22

Day 22: 註冊與登入功能 (JWT 驗證)

  • 分享至 

  • xImage
  •  

今天將為個人財務管理應用實現用戶註冊和登入功能,並透過 JWT (JSON Web Token) 進行身份驗證。這是應用安全性的重要一環,能確保只有經過驗證的用戶可以進行相關操作。

創建 User 模型

首先,要為用戶設置一個基本模型,來存儲用戶的帳號、密碼等基本訊息。接下來將使用 Mongoose 建立 User.js 模型。
在 models/ 文件夾中創建 User.js:

js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
});

// 密碼加密
userSchema.pre('save', async function (next) {
  if (!this.isModified('password')) return next();
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
  next();
});

module.exports = mongoose.model('User', userSchema);

註冊功能

接著,實現用戶的註冊功能。用戶註冊時,會創建一個新帳號並將密碼加密後儲存。此過程會使用 bcryptjs 進行密碼加密。
在 routes/ 文件夾中創建 auth.js,並設置註冊路由:

js
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');

const router = express.Router();

// 註冊路由
router.post('/register', async (req, res) => {
  const { username, email, password } = req.body;

  try {
    // 檢查用戶是否已經存在
    let user = await User.findOne({ email });
    if (user) {
      return res.status(400).json({ msg: 'User already exists' });
    }

    // 創建新用戶
    user = new User({ username, email, password });
    await user.save();

    // 生成 JWT
    const payload = { userId: user._id };
    const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });

    res.status(201).json({ token });
  } catch (error) {
    res.status(500).json({ msg: 'Server error' });
  }
});

module.exports = router;

在這裡,我們首先檢查用戶是否已經註冊過,然後創建一個新用戶,將密碼進行加密儲存,最後生成一個有效期為 1 小時的 JWT,並返回給用戶。

登入功能

登入功能允許用戶使用已註冊的憑據登錄系統。登入後,系統會生成一個 JWT,並將其返回給用戶作為身份驗證的憑證。
繼續在 auth.js 中添加登入程式碼:

js
// 登入路由
router.post('/login', async (req, res) => {
  const { email, password } = req.body;

  try {
    // 檢查用戶是否存在
    const user = await User.findOne({ email });
    if (!user) {
      return res.status(400).json({ msg: 'Invalid credentials' });
    }

    // 檢查密碼
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(400).json({ msg: 'Invalid credentials' });
    }

    // 生成 JWT
    const payload = { userId: user._id };
    const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });

    res.json({ token });
  } catch (error) {
    res.status(500).json({ msg: 'Server error' });
  }
});

這段程式碼會首先驗證用戶輸入的電子郵件和密碼是否正確,如果成功,則會生成一個新的 JWT,讓用戶登入。

保護路由:JWT 驗證中間軟體

為了確保只有已登入的用戶能夠進行某些操作,使用 JWT 來保護後端 API 是至關重要的。
在 middleware/ 文件夾中創建 authMiddleware.js,用於驗證 JWT:

js
const jwt = require('jsonwebtoken');

module.exports = function (req, res, next) {
  const token = req.header('Authorization');

  if (!token) {
    return res.status(401).json({ msg: 'No token, authorization denied' });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded.userId;
    next();
  } catch (err) {
    res.status(401).json({ msg: 'Token is not valid' });
  }
};

這個中間軟體會檢查請求中的 Authorization 標頭是否包含 JWT,然後解碼該 token 並將用戶 ID 傳遞到後續處理邏輯中。

整合與測試

在 server.js 中整合新創建的路由,讓 Express 能夠處理註冊與登入請求:

js
const authRoutes = require('./routes/auth');
app.use('/api/auth', authRoutes);

接著,使用 Postman 或其他 API 測試工具,測試註冊與登入功能是否運行正常:

  1. 發送 POST 請求到 /api/auth/register 以註冊新用戶。
  2. 發送 POST 請求到 /api/auth/login 以進行登入,並確保返回的 JWT 是有效的。
  3. 使用返回的 JWT 測試其他受保護的路由,驗證是否能夠正確通過身份驗證。

總結

今天實現了用戶的註冊和登入功能,並透過 JWT 驗證來保護應用的 API,也學習了如何加密用戶密碼,並生成安全的 JSON Web Token,這些功能就可以保障使用者的安全。在接下來的開發中,將繼續利用這些技術來進一步保護和構建應用。


上一篇
Day 21: 計畫應用實作、準備工作與專案初始化
下一篇
Day 23: 設置財務記錄的資料模型與 CRUD
系列文
30 天 Node.js 探索:基礎、進階與實踐26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言